<!DOCTYPE html>
<html>
<head>
<style>
  canvas {
    border: 1px solid #eee;
  }
</style>
</head>
<body>

<canvas id="relativityCanvas" width="600" height="400"></canvas>

<script>
const canvas = document.getElementById('relativityCanvas');
const ctx = canvas.getContext('2d');

// Helper function to draw an arrow on the canvas
function drawArrow(ctx, fromX, fromY, toX, toY) {
    ctx.beginPath();
    ctx.moveTo(fromX, fromY);
    ctx.lineTo(toX, toY);
    
    const headlen = 10;
    const angle = Math.atan2(toY - fromY, toX - fromX);
    
    ctx.moveTo(toX, toY);
    ctx.lineTo(toX - headlen * Math.cos(angle - Math.PI / 6), toY - headlen * Math.sin(angle - Math.PI / 6));
    
    ctx.moveTo(toX, toY);
    ctx.lineTo(toX - headlen * Math.cos(angle + Math.PI / 6), toY - headlen * Math.sin(angle + Math.PI / 6));
    ctx.stroke();
}

// --- Style and Coordinate Settings ---
ctx.strokeStyle = 'black';
ctx.fillStyle = 'black';
ctx.lineWidth = 1.5;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';

const O = { x: 120, y: 250 };
const O_prime = { x: 250, y: 250 };
const axis_height = 120;
const x_axis_start = O.x - 40;
const x_axis_end = 520;

// --- Draw Axes ---
// S Frame y-axis
ctx.font = 'italic 22px "Times New Roman"';
drawArrow(ctx, O.x, O.y + axis_height, O.x, O.y - axis_height);
ctx.fillText('y', O.x - 20, O.y - axis_height - 10);
ctx.fillText('O', O.x - 15, O.y + 20);

// S' Frame y'-axis
drawArrow(ctx, O_prime.x, O_prime.y + axis_height, O_prime.x, O_prime.y - axis_height);
ctx.fillText("y'", O_prime.x + 20, O_prime.y - axis_height - 10);
ctx.fillText("O'", O_prime.x - 5, O_prime.y + 25);
ctx.fillText('P', O_prime.x - 25, O_prime.y - 15);

// Common x/x' axis line
ctx.beginPath();
ctx.moveTo(x_axis_start, O.y);
ctx.lineTo(x_axis_end, O.y);
ctx.stroke();

// x and x' arrows and labels, as depicted in the original image with two separate arrows
drawArrow(ctx, 350, O.y, 400, O.y);
ctx.fillText('x', 375, O.y + 25);
drawArrow(ctx, 420, O.y, 470, O.y);
ctx.fillText("x'", 445, O.y + 25);


// --- Draw Frame Labels ---
// S Frame Label
ctx.font = 'italic 22px "Times New Roman"';
ctx.fillText('S', 190, 160);
ctx.font = '22px "SimSun", "Times New Roman"';
ctx.fillText('系', 205, 160);

// S' Frame Label
ctx.font = 'italic 22px "Times New Roman"';
ctx.fillText("S'", 300, 160);
ctx.font = '22px "SimSun", "Times New Roman"';
ctx.fillText('系', 315, 160);

// --- Draw Photon and Angle ---
const photon_len = 100;
const theta_prime_deg = 30;
const theta_prime_rad = theta_prime_deg * Math.PI / 180;
const photon_end = {
    x: O_prime.x + photon_len * Math.cos(theta_prime_rad),
    y: O_prime.y - photon_len * Math.sin(theta_prime_rad)
};
drawArrow(ctx, O_prime.x, O_prime.y, photon_end.x, photon_end.y);

// Photon label
ctx.font = '22px "SimSun", "Times New Roman"';
ctx.fillText('光子', photon_end.x + 35, photon_end.y);

// Angle Arc θ'
ctx.beginPath();
const arc_radius = 40;
ctx.arc(O_prime.x, O_prime.y, arc_radius, 0, -theta_prime_rad, true); // true for counter-clockwise
ctx.stroke();

// Angle label
ctx.font = 'italic 22px "Times New Roman"';
ctx.fillText("θ'", O_prime.x + 50, O_prime.y - 20);

// --- Draw Velocity Vector v ---
const v_start = { x: 400, y: 100 };
const v_end = { x: 500, y: 100 };
drawArrow(ctx, v_start.x, v_start.y, v_end.x, v_end.y);
ctx.fillText('v', (v_start.x + v_end.x) / 2, v_start.y - 25);

// --- Draw Origin Marker at O' ---
ctx.beginPath();
ctx.arc(O_prime.x, O_prime.y, 3, 0, 2 * Math.PI);
ctx.fill();

</script>

</body>
</html>